#include <stdio.h>
#include <stdlib.h>

void *__stack(void *ptr, int sz)
{
  static void *var[128];
  static int idx = 0;

  if(sz<0) { //top
    return var[idx-1];
  } else if(sz) { //push
    if(sz == sizeof(void *)) ptr = *((void **)ptr);
    var[idx] = ptr;
    ++idx;
  } else { //pop
    --idx;
    return var[idx];
  }

  return 0;
}

void *__locals(void *frameAddr, void *ptr)
{
  if(ptr) { //add local
    printf("ADD LOCAL TO %x\n",frameAddr);
  } else { //del locals
    printf("DEL LOCAL TO %x\n",frameAddr);
  }
  return ptr;
}

#define TOP() __stack(0,-1)
#define POP() __stack(0,0)
#define PUSH(x) __stack(&x,sizeof(x))

#define THIS teste *this = POP();
#define __ THIS

#define FRAME_ADDR __builtin_frame_address(0)
#define LADD(x) __locals(FRAME_ADDR,x)
#define LDEL() __locals(FRAME_ADDR,0)

#define D(t,x) t x = *( (t *)LADD(n##t()) );
#define RETURN(x) {LDEL(); return x;}

//#define _(o) ({ __typeof__(o) _o = o; PUSH(_o); _o;})
#define _(o) (PUSH(o),o)

typedef struct
{
  int a;
  int (*b)(int);
} teste;
teste *nteste();

int bfn(int outro)
{
  __
  D(teste,x);

  int a;
  printf("oi %d %d %d\n",this->a, outro, this->a+outro);

  RETURN (this->a);
}

teste *nteste()
{
  teste *n = malloc(sizeof(teste));
  n->a = 0;
  n->b = bfn;
  RETURN(n);
}


int main(void)
{
  D(teste, t1);
  D(teste, t2);
  teste *t3 = nteste();

  t1.a = 13;
  t2.a = 27;
  t3->a = 27;

  _(t1).b(0);

  _(t2).b( _(t1).b(0) );
  _(t3)->b( _(t1).b(0) );

  RETURN(0);
}
